{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def initialize(dims):\n",
    "    w = np.zeros((dims, 1))\n",
    "    b = 0\n",
    "    return w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def linar_loss(X, y, w, b):\n",
    "    num_train = X.shape[0]\n",
    "    num_feature = X.shape[1]\n",
    "    \n",
    "    y_hat = np.dot(X, w) + b\n",
    "    loss = np.sum((y_hat-y)**2)/num_train\n",
    "    dw = np.dot(X.T, (y_hat-y)) /num_train\n",
    "    db = np.sum((y_hat-y)) /num_train\n",
    "    return y_hat, loss, dw, db"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def linar_train(X, y, learning_rate=0.01, epochs=30000):\n",
    "    #loss_list = []\n",
    "    w, b = initialize(X.shape[1])\n",
    "    for i in range(1, epochs):\n",
    "        y_hat, loss, dw, db = linar_loss(X, y, w, b)\n",
    "        w += -learning_rate * dw\n",
    "        b += -learning_rate * db\n",
    "        #loss_list.append(loss)\n",
    "        \n",
    "        if i % 10000 == 0:\n",
    "            print('epoch %d loss %f' % (i, loss))\n",
    "        \n",
    "        params = {\n",
    "            'w': w,\n",
    "            'b': b\n",
    "        }\n",
    "        \n",
    "        grads = {\n",
    "            'dw': dw,\n",
    "            'db': db\n",
    "        }\n",
    "            \n",
    "    return loss, params, grads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(442, 10)\n",
      "(442,)\n",
      "[[ 0.03807591  0.05068012  0.06169621  0.02187235 -0.0442235  -0.03482076\n",
      "  -0.04340085 -0.00259226  0.01990842 -0.01764613]\n",
      " [-0.00188202 -0.04464164 -0.05147406 -0.02632783 -0.00844872 -0.01916334\n",
      "   0.07441156 -0.03949338 -0.06832974 -0.09220405]\n",
      " [ 0.08529891  0.05068012  0.04445121 -0.00567061 -0.04559945 -0.03419447\n",
      "  -0.03235593 -0.00259226  0.00286377 -0.02593034]\n",
      " [-0.08906294 -0.04464164 -0.01159501 -0.03665645  0.01219057  0.02499059\n",
      "  -0.03603757  0.03430886  0.02269202 -0.00936191]\n",
      " [ 0.00538306 -0.04464164 -0.03638469  0.02187235  0.00393485  0.01559614\n",
      "   0.00814208 -0.00259226 -0.03199144 -0.04664087]]\n",
      "[151.  75. 141. 206. 135.]\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import load_diabetes\n",
    "diabetes = load_diabetes()\n",
    "data = diabetes.data\n",
    "target = diabetes.target \n",
    "print(data.shape)\n",
    "print(target.shape)\n",
    "print(data[:5])\n",
    "print(target[:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(397, 10) (397, 1) (45, 10) (45, 1)\n",
      "X_train= (397, 10)\n",
      "X_test= (45, 10)\n",
      "y_train= (397, 1)\n",
      "y_test= (45, 1)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.utils import shuffle\n",
    "X, y = shuffle(data, target, random_state=13)\n",
    "X = X.astype(np.float32)\n",
    "offset = int(X.shape[0] * 0.9)\n",
    "X_train, y_train = X[:offset], y[:offset]\n",
    "X_test, y_test = X[offset:], y[offset:]\n",
    "y_train = y_train.reshape((-1,1))\n",
    "y_test = y_test.reshape((-1,1))\n",
    "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)\n",
    "\n",
    "print('X_train=', X_train.shape)\n",
    "print('X_test=', X_test.shape)\n",
    "print('y_train=', y_train.shape)\n",
    "print('y_test=', y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 10000 loss 5533.039734\n",
      "epoch 20000 loss 5217.582409\n",
      "epoch 30000 loss 4949.676466\n",
      "epoch 40000 loss 4721.504031\n",
      "epoch 50000 loss 4526.567333\n",
      "epoch 60000 loss 4359.463960\n",
      "epoch 70000 loss 4215.700505\n",
      "epoch 80000 loss 4091.538010\n",
      "epoch 90000 loss 3983.863771\n"
     ]
    }
   ],
   "source": [
    "loss, params, grads = linar_train(X_train, y_train, 0.001, 100000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'w': array([[  44.07229775],\n",
       "        [  -6.99872355],\n",
       "        [ 157.0665895 ],\n",
       "        [ 118.32921584],\n",
       "        [  37.47920655],\n",
       "        [  24.97681831],\n",
       "        [-104.31188822],\n",
       "        [ 104.03504877],\n",
       "        [ 148.85521477],\n",
       "        [  94.07047013]]), 'b': 151.57222424703687}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[132.02545017],\n",
       "       [141.77423134],\n",
       "       [150.48352021],\n",
       "       [128.48666753],\n",
       "       [147.29312454]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def predict(X, params):\n",
    "    w = params['w']\n",
    "    b = params['b']\n",
    "    \n",
    "    y_pred = np.dot(X, w) + b\n",
    "    return y_pred\n",
    "\n",
    "y_pred = predict(X_test, params)\n",
    "y_pred[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEKCAYAAAAIO8L1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3Xl81NW5+PHPAwQIsoQlKIQlbLIoIDZWK/W6VMWtglvVa621Wtvf7b5Qse29Xa20am1729rS6i22LqVqgeKCCO4bBEGRTcIqSdgJQglL4Pz+eL5DJsl3Zr6zz2Se9+uV12S++c7MYUjm+Z7nPOcccc5hjDHGNNcm2w0wxhiTmyxAGGOM8WUBwhhjjC8LEMYYY3xZgDDGGOPLAoQxxhhfFiCMMcb4sgBhjDHGlwUIY4wxvtpluwHJ6NWrlysvL892M4wxJq8sXrx4h3OuNNZ5eR0gysvLqayszHYzjDEmr4jIxiDnWYrJGGOMLwsQxhhjfFmAMMYY48sChDHGGF8WIIwxxvjK6yomkxkzl1Rz99zV1NTV07ekmMkThjNpXFm2m2WMSTMLECaqmUuquePJZdQfPgJAdV09dzy5DMCChDGtnKWYTFR3z119LDiE1B8+wt1zV2epRcaYTLEAYaKqqauP67gxpvWwAGGi6ltSHNdxY0zrYQHCRDV5wnCKi9o2OVZc1JbJE4ZnqUXGmEyxQWoTVWgg2qqYjCk8FiBMTJPGlVlAMKYAWYrJGGOMLwsQxhhjfFmAMMYY48sChDHGGF8WIIwxxviyAGGMMcaXBQhjjDG+LEAYY4zxZQHCGGOMLwsQxhhjfFmAMMYY48sChDHGGF8WIIwxxvhKW4AQkY4islBE3hGR5SLyI+/4IBF5S0TWiMjfRaS9d7yDd7/K+3l5utpmjDEmtnT2IA4C5znnxgKnABeJyBnAz4H7nHPDgN3ALd75twC7nXNDgfu884wxxmRJ2gKEU/u8u0XelwPOAx73jk8HJnnfT/Tu4/38EyIi6WqfMcaY6NI6BiEibUVkKbANmAesBeqccw3eKZuB0E40ZcAHAN7P9wA909k+Y4wxkaU1QDjnjjjnTgH6AR8FRvqd5t369RZc8wMicpuIVIpI5fbt21PXWGOMMU1kpIrJOVcHvAicAZSISGir035Ajff9ZqA/gPfzbsAun+ea5pyrcM5VlJaWprvpxhhTsNJZxVQqIiXe98XA+cBK4AXgau+0m4BZ3vezvft4P1/gnGvRgzDGGJMZ7WKfkrA+wHQRaYsGohnOuTkisgJ4TER+CiwBHvDOfwD4q4hUoT2H69LYNmOMMTGkLUA4594FxvkcX4eORzQ/fgC4Jl3tMcYYEx+bSW2MMcaXBQhjjDG+LEAYY4zxZQHCGGOMLwsQxhhjfKWzzNWYgjRzSTV3z11NTV09fUuKmTxhOJPGlcV+oDE5xgKEMSk0c0k1dzy5jPrDRwCorqvnjieXAViQMHnHUkzGpNDdc1cfCw4h9YePcPfc1VlqkTGJswBhTArV1NXHddyYXGYpJmNSqG9JMdU+waBvSXHCz2ljGiZbrAdhTApNnjCc4qK2TY4VF7Vl8oThCT1faEyjuq4eR+OYxswl1SlorTHRWQ/CmBQKXdmn6oo/2piG9SIyp1B7cRYgjEmxSePKUvbhYWMa2VfIlWmWYjIZN3NJNeOnLmDQlKcYP3WBpUuiiDR2kcyYholPIVemWYAwGWU59fikekzDxK+Qe3EWIExGFfLVWCImjSvjritHU1ZSjABlJcXcdeXoVp/ayCWF3IuzMQiTUdm4Gsv3AcZUjmmY+E2eMLzJGAQUTi/OAoTJqHTME4imkAcYTWqkujItn1iAMBmV6asxKxM1qVCovTgLECaj0nU1FimNVMgDjMYkywKEybhUX41FSyNlOqVlTGtiVUwm70VLI1mZqDGJsx6EyXvR0kiFPMBoTLIsQJi8FyuNVKgDjMYky1JMJu9ZGsmY9EhbgBCR/iLygoisFJHlIvI17/gPRaRaRJZ6X5eEPeYOEakSkdUiMiFdbTOti802NiY90pliagC+5Zx7W0S6AItFZJ73s/ucc/eEnywio4DrgJOAvsDzInKic67p6KMxPiyNZEzqpa0H4Zyrdc697X2/F1gJRPsLngg85pw76JxbD1QBH01X+4wxxkSXkTEIESkHxgFveYe+LCLvisiDItLdO1YGfBD2sM1EDyjGGGPSKO0BQkQ6A08AX3fOfQjcDwwBTgFqgXtDp/o83Pk8320iUikildu3b09Tq40xxqS1zFVEitDg8LBz7kkA59zWsJ//CZjj3d0M9A97eD+gpvlzOuemAdMAKioqWgSQfJLvq4waY1q3dFYxCfAAsNI598uw433CTrsCeM/7fjZwnYh0EJFBwDBgYbral222cY4xJtelswcxHrgRWCYiS71j3wWuF5FT0PTRBuALAM655SIyA1iBVkB9qTVXMNkqo8aYXJe2AOGcexX/cYWnozzmTuDOdLUpl9gqo8aYXGczqbOkkLcxNMbkBwsQWWLLQxhjIpm5pJrxUxcwaMpTjJ+6IGtjk7ZYX5bYKqPGGD+5tE2uBYgssuUhjDHN5VIBiwUIYzLI5r6YWHKpgMXGIIzJEJv7YoLIpQIWCxDGZEi01IExIblUwGIpJmMyJJdSByZ35VIBiwUIYzIk1taoxoTkSgGLpZiMyZBcSh0YE4T1IIzJkFxKHRgThAUIYzIoV1IHxgRhKSZjjDG+rAdhjDFJaM2THy1AGGNMgnJp3aR0sBSTMcYkqLVPfrQAYYwxCWrtkx8txWSMMQnKxuTHTI55WA/CGGMSlOnJj5le8NEChDHGJGjSuDLuunI0ZSXFCFBWUsxdV45O2xV9psc8LMVkjMk7uVRamsnJj5ke87AehDEmrxTyvhqZ3ivCAoQxJq+09tLSaDI95mEpJmNMXmntpaXRZHrBRwsQxpi8Uuj7amRyzMNSTMaYvGL7amRO2noQItIfeAg4ATgKTHPO/VpEegB/B8qBDcCnnHO7RUSAXwOXAPuBzzrn3k5X+zIlHdUWuVTBYUym2b4amSPOufQ8sUgfoI9z7m0R6QIsBiYBnwV2OeemisgUoLtz7nYRuQT4ChogTgd+7Zw7PdprVFRUuMrKyrS0PxWaL+QFeqWTTJ10Op7TmHB2AdL6ichi51xFrPPSlmJyztWGegDOub3ASqAMmAhM906bjgYNvOMPOfUmUOIFmbyVjmqLVlPB0XAQdr2f7VaYZgq5hNS0lJExCBEpB8YBbwHHO+dqQYMI0Ns7rQz4IOxhm71jzZ/rNhGpFJHK7du3p7PZSUtHtUWrqeB4+1fw17Fw+N/ZbokJ02ouQExKpD1AiEhn4Ang6865D6Od6nOsRf7LOTfNOVfhnKsoLS1NVTPTIh2TWjI9USZtql+FhgPw4cZst8SEaTUXICYl0hogRKQIDQ4PO+ee9A5vDaWOvNtt3vHNQP+wh/cDatLZvnRLR7VFq6jgcA62emNHezZktSmmqVZzAWJSIm0BwqtKegBY6Zz7ZdiPZgM3ed/fBMwKO/4ZUWcAe0KpqHyVjoW8Mr04WFrsq4F/b9HvP9yQ1aaYplrFBYhJmXROlBsP3AgsE5Gl3rHvAlOBGSJyC7AJuMb72dNoBVMVWuZ6cxrbljHpmNSSyYkyabE1rPLMUkw5xUpITbi0BQjn3Kv4jysAfMLnfAd8KV3tMTlkyyKQtnBcH0sx5aC8vwAxKWNLbZjM21oJvU6C4t6w13oQJjfY/I+WYo5BiMiXRaR7JhpjCoBzsKUSjq+AbuXWgzA5weZ/+AsySH0CsEhEZojIRd7gc6s0c0k146cuYNCUpxg/dUHB/3Ics3czzDgX9qxP/rk+3AgHdmqA6DoQ9m+Fw1ZCabIr0PyP/dtg7RzYuVInehaAmCkm59z3ReS/gQvRgePfisgM4AHn3Np0NzBTmi9hEbqCAAq+m0nlPfDBi7BhLoz9YnLPFRqgPuE02LVKv9+7CXpYlYzJnkDzP16aDCse0u+ljV7gdD8RSobp7ZDLoNugDLQ2cwKVuXoDyFu8rwagO/C4iPwijW3LKJtBGsGB3bDsz/r99mXJP9+WRdCmCHqN1j8wSF2p6/tPwIq/pua5TEEJNP+j9g3odzZc8jc4/ftwwulQvwNWTIcXvgqPfbzV9Sxi9iBE5KvofIUdwJ+Byc65wyLSBlgDfCe9TcwMm0EawTt/0OUwOveFHSkIEFsroXQMtOsAXcv1WKpKXV/+jqYBhk6C9l1S85ymIEyeMNx3Ecxj8z8O7Ibda+Ckm2HkDU0f7BysmwMzL4eVD8Poz2Ww5ekVpAfRC7jSOTfBOfcP59xhAOfcUeCytLYug2wGqY+Gg7DkNzDwQhj8SQ0Qyaz+647C1sU6/gAadNq0S81Add062LMODu+DVY8FfpiNOxkIMAF1S1hqtDkRGHwZlJ4ClXfr73krETNAOOf+xznne4nnnFuZ+iZlh80g9bHyYZ3xfNpkTQkdrIN9SXyA1q2Fg3sa/8jatIUu/VPTg9g4T2+POwHenRboIXlVubLjPXj+S3C0IdstabUmjSvjtSnnsX7qpbw25bymY49bFurt8RFWyBaB076j42pr56S/sRliO8p5WsUSFqnkjurgdOkpMOATUDpajyeTZtqySG/D/8i6DkzNGMTG5zTYfPS7msbaGnuvqbwZd3IOnvs8vPN7raAxmbdlIXQfDh1LIp8z/Br9fV7UaoZmLUCEi3oFUWjWPQ27VsJp39aro15egEhmoHprJbTrCD1HNR7rWp58D+LoEdi0AAZeAKNu1NdY9qeYD0vbuFPDAXjh67DsATgYbQHjgN7/B9S+qd/vXJH885n4OKcBos9Ho5/Xph185FtQ8xpUv56ZtqWZBQjjr/IevSI/8VN6v2N36FyWZA+iUnskbYsaj3Ut18X7jhxK/Hm3Vmr6a+AFeoU3/FpNjx3aF/VhaRt3WvNPePvX8Nyt8IcT4OkbYeP8xHLTDQfhlSkaVKWNBm2TWfuqNdV6vM/4Q3OjPwcde+hYRCtgAcK0tGURbH4JTv160w/zXqMTDxBHj8C2t1vmcLsOBBzs/cD3YYGExh8GeEt8jb4NDu2F1X+P+rC0jTutekSD6XWvwajPwLp/wePnw5/K4dXvazVMUEt/qxMUz7kPug22HkQ2hMYfYvUgAIqOg1O+DFWzYOeq9LYrAyxAmJYW3Q0dusGYzzc93mu0fkAdORz/c+5apeWyzatAupXrbTKVTBvnQe9ToZO3gVTfj0HPk2IOVofGnYaVONpxJDXjTvU7YcOzMOJ6KDsTLvgDfKEWLn1M27TwLnhwOCyfHuy53vwplF8E5RdqL8ICRDAffgCLf5XY72pzobk7pWODnT/uy1rGvfje5F87yyxAFJBAJZ1162DNEzDmiy3nEpSOgaOHYXcCe0kfm0Ht14Mg8YHqQ/ug5g1NL4WIwJjb9Mpv29LIjwUmDTnKvG63UnXRS6kZd3r/ca00GvGfjceKimHEtXDVM3DbB9rTmXsLrH82+nO9+RM49CGcfY/e7zFS33urZIpu9xp4bDy8+I3Gmc/J2LLQm7vTMdj5nUp1vsSKh2BfXm9pYwGiUAQu6Vx8ny7FfepXWz5JryQqmbZUave7e7P0Ted+mltPdKB680satMIDBMDIT+sf9LtRBqsbDsKca3Q9qFAaIVmrHoEeI6D3Kf4/79wXLn9C38t/Xa3zQvzsXgNLfwejb9WVb0F7EEcPa7mw8bd9GTx2lhYKdB8OC6dqejNR7qj2IE4IkF4K95FvwtEG3n/2zryeZ2MBokAEKums3wnvPagzRTv3bfkkPUZo8EgkQGyt1DRQm6Y5f9oWab4+0R7ExnkaCMrGNz1e3ANOvAZW/k1TW35e/AbUvqX/rp3Lk5sECJrW2Pyy9h6irWnZoStc+TQU94InL9FeW3Mv3w5tO8KZP2o8Fqr+sjSTvy2VMOMc/R279mU462dQV6VVYInatVrHs+INEN2HUl16CSds+At1e3bm/jybCCxAFIhAJZ1Lfw8N+6Hi2/5P0q6DLqoXb6nrkcOwfan/LFRIrtR14zwo+w//7v/o2zRFs3pGy58tnw7v3K+Tm8Z+UZdS2L+t5XnxWO3N4B5xfexzO/eBK5/VdNGTF8H+HY0/2/wKVP0TPnq7TvwL6TFCb62SqaXNr8A/ztOxs2tfgZ4jdMmVHiPhrZ8lHvxDc3eCDFA38z81F9NV/s11HeceO5aT82yisABRIGKWdDYcgCX/C4Mubkxp+Emkkmnncn3+SLNQuw5MbJB6b7VeTTdPL4WUjdcPiOaD1duWwvNfhP7nwsfv1HMg+Q/elY/olWb3ocHO7zkCJs3WCq6Zl8Hh/ZrSeOlb2qv6yDebnt++M3QZYD2I5jY8B09M0Pfs2legZLAelzZw+h36+7ouwdnNWxZCUeeWqdEAFuweyOuHxnBL8SyKaBwsz6f13SxAFIiYJZ2b5kP9di3Ri6bXaE0HHdob/MW3RBigDulWrrXm8Q6+bnpebyMFiNBgde2bsP1dPXZgN8y+Cjr2hMse08lNqUjd7FyhvaSR/xn73HBl4+GSR6B2Icy5TudvbFmkgauoU8vz461kOnJIlzdprdbMhJmf1A/wa1+CLs2KDEZcrz3Ut+5MrBexZaH+3jZPjQbQt6SYP+6/ir5td3B1x/lNjucLCxAFIuZSIlWztGppQIvtwps6NlD9XvAX31qpXf+SIf4/7zIQ3BHdmCgeG+dBp96Ny4D4GXUjtO2gg9XuKDxzo16xf/JxfSzolWf7LsktY7HqUb1iDU0sjMewK+C8/9X5Es/eDL3Habv99BypJcNBJ9299t/w0CnJj6/koq1LdKC/96nwqQWN/5/h2rTTVF3tW/DBC/E9f8NB2P5O/OMPnskThrOQ01h2eAh3dfktT5V8lS92nsX3z4myXMfhf+uy9U/dAL/triXnWWR7UmdbzRv6S9j3TK2TT+BKJaiIm9G7o/rhVH6xjjNEE74mU9+PBXvhrZVw/Ef0A9RPaC7Ehxsav4/FOdj4PAw4P/LzAhT3hGFXwcq/aopm3VPwid9D3zMazxHRNNOuBHsQzml6qf95OraQiHFf0l7Uop/D2fdG/jf1GAUN9TpmE2Rzmo3z9H3dV9Py6jrfLfuzFjlc+bTO9I/kpM/CGz/WXsSA84I//453tQeWYIAI/a1NnnsvZ+x9hk8d9yJTiv4Erz8A1Rdopd2wK/Q11s2BNU/qHJqGA1rA0L6LjgtWfDt60UMaWYDIpl2rNXcaStd06KaBouzj0He8/mIWZaA7WrtQlxIYOjH2uV0Hak426EB1w0FN7zTPpzd5znK9jWegescyLU+NlF4KN+Y2LT9dOFVnNvvtitdzlO6Yl4gtC3Wp8TP+O7HHh5z1M6j4lga1SMLTYbECxKF9evEBetuaAsSRQ1oUMGRS9OAAWsBQ8S146dtQ82bTi4Noar3S50jFFQE0XpR5f1s7V2ll3cq/aW92Xic4ekjTq53LYPTnYdiV+hmw6lF45jNQ83rLKr0MsQCRLYf/rbnwNu3h+te1tr36Vf1a/z09p00RjPsKnJPmGZlrZ2lXfNAlsc+VNtDr5OAD1Tve1dr9SOMPoGs+QXwD1aHlNYIEiH7/4c2CFTj/fv+rsR4jYflf4EBd9BU7/ax8RNNYw66I73F+ogUH0BQTaDps8KXRz92yqDEVtf0dGBzg/zdfrH8GDuyKnIprbswXtJrprZ/BFbODPWbrIuh0fOPvZyr0HAEf/ymM/zFUv6Z7l7TvrEHhhNOa9hyHToJ2xTouZQEiM2Yuqebuuaupqaunb0kxkycMz/yqraHlm3eugKvmaqqm78dg1Kf15/W79Kph5cOw+JfQ5wxdSjhdqmbpVopBPxh7jdbZ1s7F7vqGBqgjVTCBprU6942vB7HhOf1QD3JVLALXvaLzCsLXlgoXujLftTJ46gz0ym/133XDmA7dgj8uUR27a+lrkIHq2jf0trhXY0+itVjxVx1zKL8w2PntO8OpX4PXf6A92tIxsR9Tu1B78elI70gb6HeWfkXSvgsMmahl2uf+OvLvbhoV1CB1zmwQs+S32n0c/xMo97kCLu6hG6Bf/JBeVTz/BS3pTIfda/RDcUiA9FJIr9F69fbvAMsIbK3UiqHQkhqRdIljX4iGA1D9crDeQ0j7LtH/wI5dmcc5DrHpBU11xVu9lIyeo4KNl9S8oXMn+o5vXQHiwG4dMxtxvfZ8gxr3Ff09eOuu2Oce3KPFAEmkl1Ji5A1wYGfi6c8kpS1AiMiDIrJNRN4LO/ZDEakWkaXe1yVhP7tDRKpEZLWITEhHm3Jig5jq1+Glb+oWnqffEfG0mUuqGX/3K5y34lbq6+vZ9o/r07OVYdUsvR16efDHhAaqQ6Wj0WxZ5HWdY1yFdSsP3oOofk2DRDwBIpau5ZqrjreSadUj0L5rsPRcqvQYqe2MVpnknJb39vmYptd2vw+H86f+Pqr3/6FjEEHTSyEdu8PY/4L3Z8ReUXfrYsAlNEEupcon6AXWyoez8vLp7EH8BbjI5/h9zrlTvK+nAURkFHAdcJL3mN+LSMrLedK2QUxQ/96qa/90Hai9gwiVKuE9nXVHyvjxvlvpvfsVlv3rJ6lv09pZukdDrCv8cEHXZDq8XyfJRRt/COk6EPZuCrZuzsZ5euXY/+zY5wbVpq3W0sdTyXS4XlNtw64KvpBbKvQcpTPE99VEPqeuCup3aLqs91i9uNgZR2lyLlvxVw2SvU+N/7Ef+Qa0bQ8Lfx79vGO7H2a5B9G2CIZ/Sv9O45l7lCJpCxDOuZeBXQFPnwg85pw76JxbD1QBKQ/dSW8Q8/4T8MxNWpkTr6MN8NR12j3+5BNR8/3NezqPHpjAvIMf5cT374xv/kEs+7frWEeQ6qVwxT3huD5RA8TMJdV84ZcPgDvK7a+2j53G61qu71GQtNXGeXpl3Hy12WTFOwlt/dP6R5vJ9BIEm9hX4+1o1vdjjctUb2sFaaY967WQY9RnEhsbOO54OPlWWDG9sUrJz5aFUDJU073ZNvIGLW2umpnxl87GGMSXReRdLwUVqk8rA8J3jNnsHWtBRG4TkUoRqdy+fXtcL5zwBjHOad7yX1frEr6JdPde/R588CKc/we9oouiZY9GmLL3q+x1x8HTNyQWoPysm6NXlvGMP4T0Gh2x1DXUA6o4tIAjrg0L6gbFHusJ9WBiVTLt3wHblqQ2vRTSc5SmuSIt7tfcqke0yqX/ualvSzRBlgapeUNTXz1HaTlsUefWMQ6x4m+A6Idmos78oZaUzr4q8vpbtQuzP/4Q0vdMvYDKQpop0wHifmAIcApQC4TqN/0uBXwTrM65ac65CudcRWlpaVwvHnM2sZ8jh3XryFe/q6t0lo7R7QTjGQ+omqUbmY/9Ipz0mZin+/VodroSph6drHn/174f/LVjtavLgMhLU0fTa7R+QPksj3H33NUc17CDTxc/w8yDZ7PddY891nNsLsSG6K+7aT7g0hMgjn3wBtgJ7NBenXQ3/Nq0Tm701am3bmsZrQdR+4ZWv0kb/Sodk5kA8eEmTS2mg3M64bH/OdA1idLT4p5w+ZNwYAfMubbl7/C+Wti3OeEJciknor3UjfM0TZ1BGQ0QzrmtzrkjzrmjwJ9oTCNtBsL/x/sBURKsiZs0rozXppzH+qmXxt4g5kAdPHmxLoF9xv/AJX+D027XD5C1ARf/ajgAC76i3fxzfhXoIZF6Oh+/8CYY+/+g8l7YtCDY60dyeD9sfA6GXJ5YV710NBw56DvYV1NXz22dnqQ9h/nt/uuaHI+o6wC9jTVQvWGulpMGGdeI17HUTYCB6s0v679/SByD+6kiEj0ddmivpiLDy3VLx+iclHQuuVH9OvzfcHj8wtTs5NbcloX6+xbv4LSf40+F8/+ovfqXpzR7HW/8IVcCBGiPyR2NuY1uqmU0QIhI+DoEVwChhPps4DoR6SAig4BhQIp2cEnQnvXw6Jn6QXDRdBj/I/3DPNEbZF70i2DPs/R3uvbPOb+MvYyFJ2pP5+x7oPuJOhZyYHfi/76Nz2teM97xh5BeXh25zzjESSX13Fj8NDMPns36I40BOOpYT1EnvTKO1oNoOKjLYA+5PL7yxqBKhurzBhmH2DRfJ8f1PTP17Qiix8jI7axdqB8mTQLEWC3dTHRZ9Vh2rtJF89p3hZrX4PX/Sf1rrPirFgMMuyo1z3fSZ3RxysX36oS1kC0Ldd+TRHrW6dJzlBaTrHokoy+bzjLXR4E3gOEisllEbgF+ISLLRORd4FzgGwDOueXADGAF8CzwJedcEttAJanmTXj4dB0wvfq5pmmhtkW6bETNa1puGc2BOl3/pXxCfGvAEKWnU9RJezL7t+i4RqLWztIr8X4JVgL1HBlx86D7Bj/fovcQaKwn1r4QG+bCwbpg+y0kom0RlAwLtuz3pvk6uzUTS6H46TlK6+P3+4zDhSbInXB647HQQHU60kz7anVPizbt4Po3dGmThVN1tnOqHDmkH+JDJumGS6lyzr06T2TuLY1jalsWaQrVbzXdbBp5gy46uLsqYy+Zziqm651zfZxzRc65fs65B5xzNzrnRjvnxjjnLnfO1Yadf6dzbohzbrhzLoW/WXFa+y/4x7laIXP9G5rvbG70LZoDjrXS4qKf61X+WVNT28YTKnShr2i7pUVz9Ij+OwddkvjszHYdofuwlgPV+7cxrPYhqvtcwaEuQ4OP9YD2zKL1IFY9qjXhA85PrM1B9IxyZR6yf5uOBcVa+TadolUy1byuCz+GV8r1Gg1I6gPEwQ91V7z6HbpoXslgTaWWjoGnb4x/hd5I1j+rATEV6aVwbdvDJ/+hF0uzr9BVDLYszP78Bz8jrgMko72IgppJHdPqGTD7Suh5Mvznm7puip+i4+CUL+lV+M4IA5p7q+HtX2nUT0dX9eSbNde85sn4H1v7pu79kEj1Uji/zYMW3Q1HDjLg4p8FH+sJ6Vqug5x+BQCH9un7Pfya9C450HOUrosVrVJsk7dsdDYDRI8IM7/dUf3/bb5cSPvOutx6kMmNoEuZLL0/eu39kUNaCbTzPV0+/fiP6PGiYrhsho7RPHUHXYSyAAAU4UlEQVR9/Pt8+FkZ59Ia8ejcR9v/4SZdPPNgXW6NP4R06adzf1Y+nLHl2y1AhCx/SH+Z+5wB18yHTjEqpMZ9Wa+iK+/x//kbP9Q/1vE/TXlTASg7C7oN1gXm4lU1SxcCHHRxcm3oNVpXMT20T+/v36ZjLiNvgB4nxv98XQfqh4pfpcba2TpmMiLNcw56jNK9KeqizLTdNF9z7aEPxGzo0k9LV5unw3a9r73WPj7rSZWODdaDcA7mfg7m/xdM6w8vfadlT8Ad1XM2PQ8X/hkGNZsT22M4XDBN5yy8luR4xIHd+v8f79Ia8Sg7U9c72hra3CpHSlybG3GDzorfujgjL2cBAuCdP8KzN2k9+1XPBstxduoNJ31Or2yaz2jduVIrn8b+V/D9DeIlouvcb1oQ/3ada2fpvzXZXG5oRvXO5Xrr9R44PcEy3PB9IZpb9Sh07pf+VS3DV0uNZNN8TT2m68MqiEiVTKHxB78FB0vHau8oFNAj2bpY96Y47TswcIIO4v55EDx1Ay++9DTjpy7g/p9eCysfZsXg2+Gkm/yfZ+T1unz1wrs0RZSoRJfWiNfYL8LJt+jcllAKL9eceLWmxTI0J8ICxOJf6f7Egy+FK+Zo+iioim9q9/nt3zQ9/up39XlOT2IQOYiTbgIElk8P/pidq/QKJNHqpXDH1mRalnzvARonyzUfqK7fpQPUI66LvjlQKnQfDkjkcYg9G7TXlM30UojfeEnNG9ChRK/gmysdC7jYS6RUzdQChNO+A5/8O9yyFsZ9lcNrZnNO5aX8WW7h/3V6nL/WX8JVb58dfQLkub/WC4lnkhiPSGZpjXiIwIV/glvXZzf4R9OxBAZdqnthBFmWJkmFHSDevBNe/IaWzV3+ZPzr6ZQMgWFXwzv362AdaC141UydL9GpV+rbHK7rAP2gWv6X4BP31nqL86Wifr/bIA2EO5Yl33uAyLOp1zyhe0qkq3opXFGx/rsiBYhN3t7CuRAgeozSSrsDdY3Hat/Q3oNfIO0dsJKpaqbuoRHam6JbOZxzL5cceISf7LuVTnKAOQfO4gf7vkD94aPHJkDOXFLN+KkLGDTlKcZPXaCBo6hYB4Eb6hMbj/hwo7e0xo2Z2VVNJHuVaUGNvEE3+Ep2LlQAhRkgnNMS0de+r2/2ZY9pty0Rp03WhdPenabP+8rtul7/R76e2jZHcvLNmpL54KVg51fN0tx5l37Jv7a00WqZD17QrRGT6T2AVo517AF7m/UgVj2qcz96j0uuvUH1HBW51HXTfP3/zYUURPgeFqDzHHYs9x9/AJ0136EkeoDYvUZThkMntfhRVV0bHqifxNm7/syX997OUXQyZ01dffSl9HsMhwv+qB/0S38X379x7b/09sSr43tcazb4Uq3mC7ppVxIKM0C8/7juLDX6Vp0El0x38oQKnePw9n1aUVT9Knzsh/GlqpIxdJIOmAYZrK59SytchqZg57OQUCXTkQPJ9R5CupY37UHsrdbZriOuz9y+vD1Gwu7VLa92ndOrtv7nZW2P4Caa72FR+xbgIm94JKLlp9EW7Tu2/HvLFGS0xS5jLqU/8gZNEa2Kcybwujma9us+LL7HtWbtOsJtH2iKO80KM0AMu1KX277gj6lZR+e07+hA9TM36pXuyZ9L/jmDKuqkufn3H49ekthwEJ69WXsO476SutcPjUMk23sI6Tqw6RjE+zMAl5n0UkjPUTooumd90+M7V+jmQLmQXoKWe1jUvAFI9BLN0rHekhsRUpJVM7Wn5rP8e7TFLgMtpT90ol6gBF1P6NA+7Z0OvizY+YUkQ2mwwgwQbdp6Oc0U/fMHXqhXZg31cNZdmd8a8KSboWG/zuOI5M0fayrigmmpnYk68AL9QD0jRUsrdCvXlFmoznvVo3rl6Tfomi6RJqGFxh8Gpj5A+ObvY2nTFrqPaNzDovYN3S882v9v6VidXFm3ruXP/r3VW/69ZXoJoi8BE2gp/SETAdeYNopl4/MaqIdYgMiWHB2qzz1R97IWgXN/o6t7pjJ9E1Sf03Vryff+T2d5N7f1bd0g5aTPtqxXT1bPUfDZ5al7vq7lGmjrd2hOfcsi+I8YM9ZTrYc3QXLnyqaplk3ztTAhns2VAgjl70MpmlD+Hog9wbDnSP1QD02QG35d9PPDl9zoPrTpz9bOBlzEABFqj1+bJk8Y3uTfAD7Lq5SO0fdu7SwYc2v0doKmlzp006UwTFYUZg8iToH2su5/Npz9i+zkpkW0F1Hzmk6UCnfkEMy9WedtnPPLzLctXsdKXTdoKR/oktqZ1KGrzrkI313uaIOOhfSPb02tIJLaCje0h8XWxRpQI40/HDv/JO05+w1UV83UCq7Q/JY4BFpKX0R7EZuej71EjDsK65+C8osy3yM3x1iACCAn9rKOZdSn9Q9/RbM5EQun6vIK5/9B9+TNdaF9IfZsgJWP6IzxZNb+T1TPkU0ny21drNVqaRh/SGor3FA67L0H9TZSBVNIUbGOkzUPEIf26gf30EkJX+QEWkp/6ERdAn/Dc9GfbNsSLeUcfGlCbTGpYQEigKzvZR1E5756tbV8euMEmu3L4M2f6vIUQ7Owb0EiQj2ItbN1zCTT23mGhEpdQ4O5x+Y/pL4HkdRWuKE1mUILGQap9vFbcmP9s9rbjJJeSomys7TUNjQfJ5K1cwCB8iSXgzFJsQARQNJ7WWfKyTfrEgmbnteUyNybtddw7q+z3bLgOpZo3nnVo1p+PCxL9e89RmoaZK+3E+6m+ZpDj7VGVwIS3goXGvewOLgH+p4R7Oq/dKympcIn2FXNhOJe6c/3ty3SXsHaOdEnza2bo+mydE82NVFZgAggqT/gTBr8SZ1o9t7/waJ7NC3yid/l3x9Z14G6YN7AC7LX9vDd5Q7X694faSpvTWgr3JC2RZoyguCbF4UGqnd4K7seOaT5/iGXZ2b71CETdenumtf9f76vVhfNs/LWrLMqpgBCf6gRq5hyRbsOOh/h3T/qFeGwq/JzBmrXch03yeTch+bCS13bFOkyImmc/xCpOiiQ0O5yscYfQkIBYts7uqTGBy9pDyTd6aWQQRfpygVVs/T1m1v/tN5agMg6CxABJfUHnEknfRaW/K/2JD4R57IGuaL7cJ2JnqkPLD/FPaG4VMch6ndoGsfvwywXHH+qfqgGXaK6c18OFnXnufnP8NUZg7m3xzQuLyqmXTo3YgrXvosG27WzdAvd5mmxdXN0WZBeJ2emPSYiSzG1Nr3H6Zaol/wNjjs+261JzBnfg0+/rR8k2RRaTnvTfJ2dnO32RHLqN+CmZbopUAAzl9bw9v4BDDhSBRzlTF5lwYFTmfnervS2M9yQibr0ePPJiA0HYOM87T3kwnImBc4CRGsjovvsJrsZUDZ16JaaZTuS1XOkprq2VubO8hp+iop1Al9Ad89dzfLD5Qxvt5Fx7VZzQttdPHPg9MyWbQ/5pN42r2ba/JIWB9js6ZxgAcKYSHqMgsP7tNQ1lwNEnGrq6lnZMJiOcogvdHqCBteGBYdOy2zZdue+2iurahYg1s6BdsXQ75zMtcVEZAHCmEhCq6W2K9ataFuJviXFrGwYBMCEDm/y1uGT2eO6ZL5se+hE2LKwcUdG53T8YcD5ub8nQ4GwAGGABBeLa+1ClUxlZ2mFWCsxecJwNrcZyGGnJa3PHfxYdsq2h3jrXK2drbc7V+gSK5ZeyhlWxWSSWyyuNTuuj87FOPnmbLckpUL/pxvnD2Ao61nW8WzumhBw3kUq9RylYydVs3Q/6HVz9PggW14jV1iAMFHXmiroACECV8dYMyhPTRpXBvuugx3v8uQVWZpvElq8b+lvdS2odXO0Cq9LAf/O5RhLMZn8WGvKpN5ZP4Mr5mS3DUMn6kzulY/ozGqbHJdT0hYgRORBEdkmIu+FHeshIvNEZI132907LiLyGxGpEpF3ReTUdLXLtJQ3a02Z1qfvmbrI4Kvf02oxCxA5JZ09iL8AzXenmQLMd84NA+Z79wEuBoZ5X7cB96exXaaZvFlryrQ+bdqxqeQ8OLCTHUdL+Pj0D61AIoekLUA4514Gmk/NnAiENiyYDkwKO/6QU28CJSLSJ11tM00ltVicMUmYuaSau9fqhcgLhyrYXHew5WZcJmsyPUh9vHOuFsA5Vysivb3jZcAHYedt9o7VNn8CEbkN7WUwYMCA9La2gOTNWlOmVbl77mp27j+Fl4pO5ZF6TThYgUTuyJUqJr9FV5zfic65acA0gIqKCt9zjDH5oaauHkdHbtrz4xbHTfZluoppayh15N1u845vBsL3lewH1GS4bcaYDLMCidyW6QAxG7jJ+/4mYFbY8c941UxnAHtCqShjTOtlBRK5LW0pJhF5FDgH6CUim4EfAFOBGSJyC7AJuMY7/WngEqAK2A+0rqmrxhhfebMZV4ES5/I3jV9RUeEqKyuz3QyTQjOXVNuHRYrYe2kiEZHFzrmKWOflyiC1MbYmVArZe2lSwZbaMDkj2ppQJj72XppUsB6EyRm2JlTq2HuZ+/IhBWg9CJMzrOQxdey9zG2hFGB1XT2OxhRgrs0gtwBhcoaVPKaOvZe5LV9SgJZiMjnDSh5Tx97L3JYvKUALECan2JpQqWPvZe7qW1JMtU8wyLUUoKWYjDEmw/IlBWg9CGMiyIcqE5Of8iUFaAHCGB820cykWz6kAC3FZIyPfKkyMSadrAdhjI98qTIx8bG0YXysB2GMD5to1vrky+S0XGIBwiRs5pJqxk9dwKApTzF+6oK0/6Fl8vXypcrEBGdpw/hZiskkJNODuJl+vXypMjEtRUojWdowfhYgTEKiXY2l40M0068H+VFlYpqKdiGRL5PTcomlmExCMn01Zld/hSnetGK0CwlLG8bPAoRJSKYHcW3QuPAkMqgc7UJi0rgy7rpyNGUlxQhQVlLMXVeOtl5iFJZiMgmZPGF4k648pPdqLNOvZ7IvkbRirDSSpQ3jYz0Ik5BMX43Z1V/hSSStaGmk1LIehElYpq/G7OqvsCQyqGzVZ6llAcIYk5MSTSvahUTqWIAwxuQk6w1knwUIY/JYvqwtlGg7rTeQXRYgjMlT+bIkeb6007SUlSomEdkgIstEZKmIVHrHeojIPBFZ4912z0bb8l2m10cy2ZMvawvlSztNS9nsQZzrnNsRdn8KMN85N1VEpnj3b89O0+KTK918u1IrLPkyuzxf2mlayqV5EBOB6d7304FJWWxLYLm0hLBdqRWWfJldni/tNC1lK0A44DkRWSwit3nHjnfO1QJ4t739Higit4lIpYhUbt++PUPNjSyXPpTtSq2w5MuksHxpp2kpWymm8c65GhHpDcwTkVVBH+icmwZMA6ioqHDpamBQufShbKtVFpZ8KQPNl3aalrISIJxzNd7tNhH5J/BRYKuI9HHO1YpIH2BbNtoWr1z6ULb1igpPvpSB5ks7TVMZTzGJyHEi0iX0PXAh8B4wG7jJO+0mYFam25aIXOo+23pFmWPVYqYQZKMHcTzwTxEJvf4jzrlnRWQRMENEbgE2AddkoW1xy7Xus12ppZ9Vi5lCIc5lPY2fsIqKCldZWZntZpgCM37qAt+0YllJMa9NOS8LLTImPiKy2DlXEeu8XCpzNSYv5FJhgjHpZAHCmDhZXb8pFBYgjIlTLhUmGJNOtlifMXHKtcIEY9LFAoQxCbBqMVMILMVkjDHGlwUIY4wxvixAGGOM8WUBwhhjjC8LEMYYY3zl9VIbIrId2Jjgw3sBO2KeVXjsfWnJ3pOW7D1pKZ/ek4HOudJYJ+V1gEiGiFQGWYuk0Nj70pK9Jy3Ze9JSa3xPLMVkjDHGlwUIY4wxvgo5QEzLdgNylL0vLdl70pK9Jy21uvekYMcgjDHGRFfIPQhjjDFRFGSAEJGLRGS1iFSJyJRstycbRORBEdkmIu+FHeshIvNEZI132z2bbcw0EekvIi+IyEoRWS4iX/OOF+z7IiIdRWShiLzjvSc/8o4PEpG3vPfk7yLSPtttzTQRaSsiS0Rkjne/1b0nBRcgRKQt8DvgYmAUcL2IjMpuq7LiL8BFzY5NAeY754YB8737haQB+JZzbiRwBvAl73ejkN+Xg8B5zrmxwCnARSJyBvBz4D7vPdkN3JLFNmbL14CVYfdb3XtScAEC+ChQ5Zxb55w7BDwGTMxymzLOOfcysKvZ4YnAdO/76cCkjDYqy5xztc65t73v96J//GUU8Pvi1D7vbpH35YDzgMe94wX1ngCISD/gUuDP3n2hFb4nhRggyoAPwu5v9o4ZON45Vwv6YQn0znJ7skZEyoFxwFsU+PvipVKWAtuAecBaoM451+CdUoh/Q78CvgMc9e73pBW+J4UYIMTnmJVymWNEpDPwBPB159yH2W5PtjnnjjjnTgH6oT3wkX6nZbZV2SMilwHbnHOLww/7nJr370kh7ii3Gegfdr8fUJOltuSarSLSxzlXKyJ90CvGgiIiRWhweNg596R3uODfFwDnXJ2IvIiOz5SISDvvirnQ/obGA5eLyCVAR6Ar2qNode9JIfYgFgHDvIqD9sB1wOwstylXzAZu8r6/CZiVxbZknJdHfgBY6Zz7ZdiPCvZ9EZFSESnxvi8GzkfHZl4ArvZOK6j3xDl3h3Oun3OuHP38WOCcu4FW+J4U5EQ5L/L/CmgLPOicuzPLTco4EXkUOAddgXIr8ANgJjADGABsAq5xzjUfyG61ROTjwCvAMhpzy99FxyEK8n0RkTHogGtb9IJyhnPuxyIyGC3w6AEsAT7tnDuYvZZmh4icA3zbOXdZa3xPCjJAGGOMia0QU0zGGGMCsABhjDHGlwUIY4wxvixAGGOM8WUBwhhjjC8LEMakiLca7HoR6eHd7+7dH5jtthmTCAsQxqSIc+4D4H5gqndoKjDNObcxe60yJnE2D8KYFPKW6lgMPAh8HhjnrRpsTN4pxLWYjEkb59xhEZkMPAtcaMHB5DNLMRmTehcDtcDJ2W6IMcmwAGFMConIKcAF6Iqn3/BWfzUmL1mAMCZFvNVg70f3kdgE3A3ck91WGZM4CxDGpM7ngU3OuXne/d8DI0Tk7Cy2yZiEWRWTMcYYX9aDMMYY48sChDHGGF8WIIwxxviyAGGMMcaXBQhjjDG+LEAYY4zxZQHCGGOMLwsQxhhjfP1/wJSXR9/OwB8AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "f = X_test.dot(params['w']) + params['b']\n",
    "\n",
    "plt.scatter(range(X_test.shape[0]), y_test)\n",
    "plt.plot(f, color = 'darkorange')\n",
    "plt.xlabel('X')\n",
    "plt.ylabel('y')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(loss_list, color = 'blue')\n",
    "plt.xlabel('epochs')\n",
    "plt.ylabel('loss')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(442, 11)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.utils import shuffle\n",
    "X, y = shuffle(data, target, random_state=13)\n",
    "X = X.astype(np.float32)\n",
    "data = np.concatenate((X, y.reshape((-1,1))), axis=1)\n",
    "data.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(353, 10) (353, 1) (89, 10) (89, 1)\n",
      "epoch 10000 loss 5667.323261\n",
      "epoch 20000 loss 5365.061628\n",
      "epoch 30000 loss 5104.951009\n",
      "epoch 40000 loss 4880.559191\n",
      "epoch 50000 loss 4686.465012\n",
      "epoch 60000 loss 4518.097942\n",
      "epoch 70000 loss 4371.603217\n",
      "epoch 80000 loss 4243.728424\n",
      "epoch 90000 loss 4131.728130\n",
      "five kold cross validation score is 4033.2928969313452\n",
      "valid score is 3558.147428823725\n",
      "(353, 10) (353, 1) (89, 10) (89, 1)\n",
      "epoch 10000 loss 5517.461607\n",
      "epoch 20000 loss 5181.523292\n",
      "epoch 30000 loss 4897.000442\n",
      "epoch 40000 loss 4655.280406\n",
      "epoch 50000 loss 4449.235361\n",
      "epoch 60000 loss 4272.963989\n",
      "epoch 70000 loss 4121.578253\n",
      "epoch 80000 loss 3991.027359\n",
      "epoch 90000 loss 3877.952427\n",
      "five kold cross validation score is 3779.575673476155\n",
      "valid score is 4389.749894361285\n",
      "(354, 10) (354, 1) (88, 10) (88, 1)\n",
      "epoch 10000 loss 5677.526932\n",
      "epoch 20000 loss 5331.464606\n",
      "epoch 30000 loss 5038.541403\n",
      "epoch 40000 loss 4789.859079\n",
      "epoch 50000 loss 4578.047735\n",
      "epoch 60000 loss 4397.001364\n",
      "epoch 70000 loss 4241.659289\n",
      "epoch 80000 loss 4107.825490\n",
      "epoch 90000 loss 3992.019241\n",
      "five kold cross validation score is 3891.3610347157187\n",
      "valid score is 3844.049401675179\n",
      "(354, 10) (354, 1) (88, 10) (88, 1)\n",
      "epoch 10000 loss 5366.435738\n",
      "epoch 20000 loss 5117.050627\n",
      "epoch 30000 loss 4902.593420\n",
      "epoch 40000 loss 4717.676380\n",
      "epoch 50000 loss 4557.767422\n",
      "epoch 60000 loss 4419.053021\n",
      "epoch 70000 loss 4298.323163\n",
      "epoch 80000 loss 4192.874781\n",
      "epoch 90000 loss 4100.430691\n",
      "five kold cross validation score is 4019.0791769506664\n",
      "valid score is 4300.006957377207\n",
      "(354, 10) (354, 1) (88, 10) (88, 1)\n",
      "epoch 10000 loss 5592.024970\n",
      "epoch 20000 loss 5278.867272\n",
      "epoch 30000 loss 5010.647792\n",
      "epoch 40000 loss 4780.303445\n",
      "epoch 50000 loss 4581.916469\n",
      "epoch 60000 loss 4410.526730\n",
      "epoch 70000 loss 4261.974936\n",
      "epoch 80000 loss 4132.771612\n",
      "epoch 90000 loss 4019.987616\n",
      "five kold cross validation score is 3921.1718979156462\n",
      "valid score is 3909.701727644273\n"
     ]
    }
   ],
   "source": [
    "from random import shuffle\n",
    "\n",
    "def k_fold_cross_validation(items, k, randomize=True):\n",
    "    if randomize:\n",
    "        items = list(items)\n",
    "        shuffle(items)\n",
    "\n",
    "    slices = [items[i::k] for i in range(k)]\n",
    "\n",
    "    for i in range(k):\n",
    "        validation = slices[i]\n",
    "        training = [item\n",
    "                    for s in slices if s is not validation\n",
    "                    for item in s]\n",
    "        training = np.array(training)\n",
    "        validation = np.array(validation)\n",
    "        yield training, validation\n",
    "\n",
    "\n",
    "\n",
    "for training, validation in k_fold_cross_validation(data, 5): \n",
    "    X_train = training[:, :10]\n",
    "    y_train = training[:, -1].reshape((-1,1))\n",
    "    X_valid = validation[:, :10]\n",
    "    y_valid = validation[:, -1].reshape((-1,1))\n",
    "    loss5 = []\n",
    "    #print(X_train.shape, y_train.shape, X_valid.shape, y_valid.shape)\n",
    "    loss, params, grads = linar_train(X_train, y_train, 0.001, 100000)\n",
    "    loss5.append(loss)\n",
    "    score = np.mean(loss5)\n",
    "    print('five kold cross validation score is', score)\n",
    "    y_pred = predict(X_valid, params)\n",
    "    valid_score = np.sum(((y_pred-y_valid)**2))/len(X_valid)\n",
    "    print('valid score is', valid_score)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(353, 10) (353, 1) (89, 10) (89, 1)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import load_diabetes\n",
    "from sklearn.utils import shuffle\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "diabetes = load_diabetes()\n",
    "data = diabetes.data\n",
    "target = diabetes.target \n",
    "X, y = shuffle(data, target, random_state=13)\n",
    "X = X.astype(np.float32)\n",
    "y = y.reshape((-1, 1))\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n",
    "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Coefficients: \n",
      " [[ -23.510405 -216.31221   472.3672    372.07184  -863.69977   583.276\n",
      "   105.79429   194.7704    754.07404    38.22214 ]]\n",
      "Mean squared error: 3028.50\n",
      "Variance score: 0.53\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x2392761ba58>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from sklearn import linear_model\n",
    "from sklearn.metrics import mean_squared_error, r2_score\n",
    "\n",
    "\n",
    "regr = linear_model.LinearRegression()\n",
    "regr.fit(X_train, y_train)\n",
    "\n",
    "y_pred = regr.predict(X_test)\n",
    "\n",
    "# The coefficients\n",
    "print('Coefficients: \\n', regr.coef_)\n",
    "# The mean squared error\n",
    "print(\"Mean squared error: %.2f\"\n",
    "      % mean_squared_error(y_test, y_pred))\n",
    "# Explained variance score: 1 is perfect prediction\n",
    "print('Variance score: %.2f' % r2_score(y_test, y_pred))\n",
    "\n",
    "# Plot outputs\n",
    "plt.scatter(range(X_test.shape[0]), y_test, color='red')\n",
    "plt.plot(range(X_test.shape[0]), y_pred, color='blue', linewidth=3)\n",
    "\n",
    "plt.xticks(())\n",
    "plt.yticks(())\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "def R2(ypred, ytrue):\n",
    "    y_avg = np.mean(ytrue)\n",
    "    SS_tot = np.sum((ytrue - y_avg)**2)\n",
    "    SS_res = np.sum((ytrue - ypred)**2)\n",
    "    r2 = 1 - (SS_res/SS_tot)\n",
    "    return r2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(442, 10) (442, 1)\n"
     ]
    }
   ],
   "source": [
    "print(X.shape, y.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cross Validating - Run 1 out of 5\n",
      "Fold 1 out of 5\n",
      "Fold 2 out of 5\n",
      "Fold 3 out of 5\n",
      "Fold 4 out of 5\n",
      "Fold 5 out of 5\n",
      "Cross Validating - Run 2 out of 5\n",
      "Fold 1 out of 5\n",
      "Fold 2 out of 5\n",
      "Fold 3 out of 5\n",
      "Fold 4 out of 5\n",
      "Fold 5 out of 5\n",
      "Cross Validating - Run 3 out of 5\n",
      "Fold 1 out of 5\n",
      "Fold 2 out of 5\n",
      "Fold 3 out of 5\n",
      "Fold 4 out of 5\n",
      "Fold 5 out of 5\n",
      "Cross Validating - Run 4 out of 5\n",
      "Fold 1 out of 5\n",
      "Fold 2 out of 5\n",
      "Fold 3 out of 5\n",
      "Fold 4 out of 5\n",
      "Fold 5 out of 5\n",
      "Cross Validating - Run 5 out of 5\n",
      "Fold 1 out of 5\n",
      "Fold 2 out of 5\n",
      "Fold 3 out of 5\n",
      "Fold 4 out of 5\n",
      "Fold 5 out of 5\n",
      "\n",
      "Overall R2: [-670.4095204  -671.45443974 -673.60734422 -671.40192667 -675.31208185]\n",
      "Mean: -672.437062575318\n",
      "Deviation: 1.77669784591671\n"
     ]
    }
   ],
   "source": [
    "import numpy as np \n",
    "import pandas as pd \n",
    "from sklearn.utils import shuffle\n",
    "from sklearn.model_selection import KFold\n",
    "from sklearn.linear_model import LinearRegression\n",
    "\n",
    "def cross_validate(model, x, y, folds=5, repeats=5):\n",
    "    \n",
    "    ypred = np.zeros((len(y),repeats))\n",
    "    score = np.zeros(repeats)\n",
    "    for r in range(repeats):\n",
    "        i=0\n",
    "        print('Cross Validating - Run', str(r + 1), 'out of', str(repeats))\n",
    "        x,y = shuffle(x, y, random_state=r) #shuffle data before each repeat\n",
    "        kf = KFold(n_splits=folds,random_state=i+1000) #random split, different each time\n",
    "        for train_ind, test_ind in kf.split(x):\n",
    "            print('Fold', i+1, 'out of', folds)\n",
    "            xtrain,ytrain = x[train_ind,:],y[train_ind]\n",
    "            xtest,ytest = x[test_ind,:],y[test_ind]\n",
    "            model.fit(xtrain, ytrain)\n",
    "            #print(xtrain.shape, ytrain.shape, xtest.shape, ytest.shape)\n",
    "            ypred[test_ind]=model.predict(xtest)\n",
    "            i+=1\n",
    "        score[r] = R2(ypred[:,r],y)\n",
    "    print('\\nOverall R2:',str(score))\n",
    "    print('Mean:',str(np.mean(score)))\n",
    "    print('Deviation:',str(np.std(score)))\n",
    "    pass\n",
    "\n",
    "cross_validate(regr, X, y, folds=5, repeats=5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/env python\n",
    "# -*- coding: utf-8 -*-\n",
    "# @Time    : 2018/8/29 14:45\n",
    "# @Author  : louwill\n",
    "# @File    : lr_class.py\n",
    "# @mail: ygnjd2016@gmail.com\n",
    "\n",
    "\n",
    "import numpy as np\n",
    "from sklearn.utils import shuffle\n",
    "from sklearn.datasets import load_diabetes\n",
    "\n",
    "class lr_model():\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    def prepare_data(self):\n",
    "        data = load_diabetes().data\n",
    "        target = load_diabetes().target\n",
    "        X, y = shuffle(data, target, random_state=42)\n",
    "        X = X.astype(np.float32)\n",
    "        y = y.reshape((-1, 1))\n",
    "        data = np.concatenate((X, y), axis=1)\n",
    "        return data\n",
    "\n",
    "\n",
    "    def initialize_params(self, dims):\n",
    "        w = np.zeros((dims, 1))\n",
    "        b = 0\n",
    "        return w, b\n",
    "\n",
    "\n",
    "    def linear_loss(self, X, y, w, b):\n",
    "        num_train = X.shape[0]\n",
    "        num_feature = X.shape[1]\n",
    "\n",
    "        y_hat = np.dot(X, w) + b\n",
    "        loss = np.sum((y_hat-y)**2) / num_train\n",
    "        dw = np.dot(X.T, (y_hat - y)) / num_train\n",
    "        db = np.sum((y_hat - y)) / num_train\n",
    "        return y_hat, loss, dw, db\n",
    "\n",
    "\n",
    "    def linear_train(self, X, y, learning_rate, epochs):\n",
    "        w, b = self.initialize_params(X.shape[1])\n",
    "        for i in range(1, epochs):\n",
    "            y_hat, loss, dw, db = self.linear_loss(X, y, w, b)\n",
    "            w += -learning_rate * dw\n",
    "            b += -learning_rate * db\n",
    "\n",
    "            if i % 10000 == 0:\n",
    "                print('epoch %d loss %f' % (i, loss))\n",
    "            params = {\n",
    "                'w': w,\n",
    "                'b': b\n",
    "            }\n",
    "            grads = {\n",
    "                'dw': dw,\n",
    "                'db': db\n",
    "            }\n",
    "        return loss, params, grads\n",
    "\n",
    "\n",
    "    def predict(self, X, params):\n",
    "        w = params['w']\n",
    "        b = params['b']\n",
    "        y_pred = np.dot(X, w) + b\n",
    "        return y_pred\n",
    "\n",
    "\n",
    "    def linear_cross_validation(self, data, k, randomize=True):\n",
    "        if randomize:\n",
    "            data = list(data)\n",
    "            shuffle(data)\n",
    "\n",
    "        slices = [data[i::k] for i in range(k)]\n",
    "        for i in range(k):\n",
    "            validation = slices[i]\n",
    "            train = [data\n",
    "                        for s in slices if s is not validation\n",
    "                        for data in s]\n",
    "            train = np.array(train)\n",
    "            validation = np.array(validation)\n",
    "            yield train, validation\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    lr = lr_model()\n",
    "    data = lr.prepare_data()\n",
    "    for train, validation in lr.linear_cross_validation(data, 5):\n",
    "        X_train = train[:, :10]\n",
    "        y_train = train[:, -1].reshape((-1, 1))\n",
    "        X_valid = validation[:, :10]\n",
    "        y_valid = validation[:, -1].reshape((-1, 1))\n",
    "\n",
    "        loss5 = []\n",
    "        loss, params, grads = lr.linear_train(X_train, y_train, 0.001, 100000)\n",
    "        loss5.append(loss)\n",
    "        score = np.mean(loss5)\n",
    "        print('five kold cross validation score is', score)\n",
    "        y_pred = lr.predict(X_valid, params)\n",
    "        valid_score = np.sum(((y_pred - y_valid) ** 2)) / len(X_valid)\n",
    "        print('valid score is', valid_score)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
